// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#ifndef CORE_SRC_FPDFAPI_FPDF_PAGE_PAGEINT_H_
#define CORE_SRC_FPDFAPI_FPDF_PAGE_PAGEINT_H_

#include <map>

#include "../../../../third_party/base/nonstd_unique_ptr.h"
#include "../../../include/fpdfapi/fpdf_pageobj.h"

#define PARSE_STEP_LIMIT		100

class CPDF_StreamParser
{
public:

    CPDF_StreamParser(const uint8_t* pData, FX_DWORD dwSize);
    ~CPDF_StreamParser();

    CPDF_Stream*		ReadInlineStream(CPDF_Document* pDoc, CPDF_Dictionary* pDict, CPDF_Object* pCSObj, FX_BOOL bDecode);
    typedef enum { EndOfData, Number, Keyword, Name, Others } SyntaxType;

    SyntaxType			ParseNextElement();
    uint8_t*			GetWordBuf()
    {
        return m_WordBuffer;
    }
    FX_DWORD			GetWordSize()
    {
        return m_WordSize;
    }
    CPDF_Object*		GetObject()
    {
        CPDF_Object* pObj = m_pLastObj;
        m_pLastObj = NULL;
        return pObj;
    }
    FX_DWORD			GetPos()
    {
        return m_Pos;
    }
    void				SetPos(FX_DWORD pos)
    {
        m_Pos = pos;
    }

    CPDF_Object*		ReadNextObject(FX_BOOL bAllowNestedArray = FALSE, FX_BOOL bInArray = FALSE);
    void				SkipPathObject();
protected:
    void				GetNextWord(FX_BOOL& bIsNumber);
    CFX_ByteString		ReadString();
    CFX_ByteString		ReadHexString();
    const uint8_t*		m_pBuf;
    FX_DWORD			m_Size;
    FX_DWORD			m_Pos;
    uint8_t				m_WordBuffer[256];
    FX_DWORD			m_WordSize;
    CPDF_Object*		m_pLastObj;
};
typedef enum {
    PDFOP_CloseFillStrokePath = 0, PDFOP_FillStrokePath,
    PDFOP_CloseEOFillStrokePath, PDFOP_EOFillStrokePath,
    PDFOP_BeginMarkedContent_Dictionary, PDFOP_BeginImage,
    PDFOP_BeginMarkedContent, PDFOP_BeginText,
    PDFOP_BeginSectionUndefined, PDFOP_CurveTo_123,
    PDFOP_ConcatMatrix, PDFOP_SetColorSpace_Fill,
    PDFOP_SetColorSpace_Stroke, PDFOP_SetDash,
    PDFOP_SetCharWidth, PDFOP_SetCachedDevice,
    PDFOP_ExecuteXObject, PDFOP_MarkPlace_Dictionary,
    PDFOP_EndImage, PDFOP_EndMarkedContent,
    PDFOP_EndText, PDFOP_EndSectionUndefined,
    PDFOP_FillPath, PDFOP_FillPathOld,
    PDFOP_EOFillPath, PDFOP_SetGray_Fill,
    PDFOP_SetGray_Stroke, PDFOP_SetExtendGraphState,
    PDFOP_ClosePath, PDFOP_SetFlat,
    PDFOP_BeginImageData, PDFOP_SetLineJoin,
    PDFOP_SetLineCap, PDFOP_SetCMYKColor_Fill,
    PDFOP_SetCMYKColor_Stroke, PDFOP_LineTo,
    PDFOP_MoveTo, PDFOP_SetMiterLimit,
    PDFOP_MarkPlace, PDFOP_EndPath,
    PDFOP_SaveGraphState, PDFOP_RestoreGraphState,
    PDFOP_Rectangle, PDFOP_SetRGBColor_Fill,
    PDFOP_SetRGBColor_Stroke, PDFOP_SetRenderIntent,
    PDFOP_CloseStrokePath, PDFOP_StrokePath,
    PDFOP_SetColor_Fill, PDFOP_SetColor_Stroke,
    PDFOP_SetColorPS_Fill, PDFOP_SetColorPS_Stroke,
    PDFOP_ShadeFill, PDFOP_SetCharSpace,
    PDFOP_MoveTextPoint, PDFOP_MoveTextPoint_SetLeading,
    PDFOP_SetFont, PDFOP_ShowText,
    PDFOP_ShowText_Positioning, PDFOP_SetTextLeading,
    PDFOP_SetTextMatrix, PDFOP_SetTextRenderMode,
    PDFOP_SetTextRise, PDFOP_SetWordSpace,
    PDFOP_SetHorzScale, PDFOP_MoveToNextLine,
    PDFOP_CurveTo_23, PDFOP_SetLineWidth,
    PDFOP_Clip, PDFOP_EOClip,
    PDFOP_CurveTo_13, PDFOP_NextLineShowText,
    PDFOP_NextLineShowText_Space, PDFOP_Invalid
} PDFOP;
#define PARAM_BUF_SIZE	16
typedef struct {
    int			m_Type;
    union {
        struct {
            FX_BOOL		m_bInteger;
            union {
                int		m_Integer;
                FX_FLOAT m_Float;
            };
        } m_Number;
        CPDF_Object*	m_pObject;
        struct {
            int			m_Len;
            char		m_Buffer[32];
        } m_Name;
    };
} _ContentParam;
#define _FPDF_MAX_FORM_LEVEL_		30
#define _FPDF_MAX_TYPE3_FORM_LEVEL_	4
#define _FPDF_MAX_OBJECT_STACK_SIZE_ 512
class CPDF_StreamContentParser
{
public:
    CPDF_StreamContentParser(
        CPDF_Document* pDoc,
        CPDF_Dictionary* pPageResources,
        CPDF_Dictionary* pParentResources,
        CFX_AffineMatrix* pmtContentToUser,
        CPDF_PageObjects* pObjList,
        CPDF_Dictionary* pResources,
        CFX_FloatRect* pBBox,
        CPDF_ParseOptions* pOptions,
        CPDF_AllStates* pAllStates,
        int level);
    ~CPDF_StreamContentParser();

    FX_BOOL ShouldAbort() const { return m_bAbort; }
    CPDF_PageObjects* GetObjectList() const { return m_pObjectList; }
    CPDF_AllStates* GetCurStates() const { return m_pCurStates.get(); }
    FX_BOOL IsColored() const { return m_bColored; }
    const FX_FLOAT* GetType3Data() const { return m_Type3Data; }

    void				AddNumberParam(const FX_CHAR* str, int len);
    void				AddObjectParam(CPDF_Object* pObj);
    void				AddNameParam(const FX_CHAR* name, int size);
    int					GetNextParamPos();
    void				ClearAllParams();
    CPDF_Object*		GetObject(FX_DWORD index);
    CFX_ByteString		GetString(FX_DWORD index);
    FX_FLOAT			GetNumber(FX_DWORD index);
    FX_FLOAT		GetNumber16(FX_DWORD index);
    int					GetInteger(FX_DWORD index)
    {
        return (int32_t)(GetNumber(index));
    }
    FX_BOOL				OnOperator(const FX_CHAR* op);
    void				BigCaseCaller(int index);
    FX_DWORD			GetParsePos()
    {
        return m_pSyntax->GetPos();
    }
    void				AddTextObject(CFX_ByteString* pText, FX_FLOAT fInitKerning, FX_FLOAT* pKerning, int count);

    void				ConvertUserSpace(FX_FLOAT& x, FX_FLOAT& y);
    void				ConvertTextSpace(FX_FLOAT& x, FX_FLOAT& y);
    void				OnChangeTextMatrix();
    FX_DWORD			Parse(const uint8_t* pData, FX_DWORD dwSize, FX_DWORD max_cost);
    void				ParsePathObject();
    void				AddPathPoint(FX_FLOAT x, FX_FLOAT y, int flag);
    void				AddPathRect(FX_FLOAT x, FX_FLOAT y, FX_FLOAT w, FX_FLOAT h);
    void				AddPathObject(int FillType, FX_BOOL bStroke);
    CPDF_ImageObject*	AddImage(CPDF_Stream* pStream, CPDF_Image* pImage, FX_BOOL bInline);
    void				AddDuplicateImage();
    void				AddForm(CPDF_Stream*);
    void				SetGraphicStates(CPDF_PageObject* pObj, FX_BOOL bColor, FX_BOOL bText, FX_BOOL bGraph);
    void				SaveStates(CPDF_AllStates*);
    void				RestoreStates(CPDF_AllStates*);
    CPDF_Font*			FindFont(const CFX_ByteString& name);
    CPDF_ColorSpace*	FindColorSpace(const CFX_ByteString& name);
    CPDF_Pattern*		FindPattern(const CFX_ByteString& name, FX_BOOL bShading);
    CPDF_Object*		FindResourceObj(const CFX_ByteStringC& type, const CFX_ByteString& name);

protected:
    struct OpCode {
        FX_DWORD m_OpId;
        void (CPDF_StreamContentParser::*m_OpHandler)();
    };
    static const OpCode g_OpCodes[];

    void Handle_CloseFillStrokePath();
    void Handle_FillStrokePath();
    void Handle_CloseEOFillStrokePath();
    void Handle_EOFillStrokePath();
    void Handle_BeginMarkedContent_Dictionary();
    void Handle_BeginImage();
    void Handle_BeginMarkedContent();
    void Handle_BeginText();
    void Handle_BeginSectionUndefined();
    void Handle_CurveTo_123();
    void Handle_ConcatMatrix();
    void Handle_SetColorSpace_Fill();
    void Handle_SetColorSpace_Stroke();
    void Handle_SetDash();
    void Handle_SetCharWidth();
    void Handle_SetCachedDevice();
    void Handle_ExecuteXObject();
    void Handle_MarkPlace_Dictionary();
    void Handle_EndImage();
    void Handle_EndMarkedContent();
    void Handle_EndText();
    void Handle_EndSectionUndefined();
    void Handle_FillPath();
    void Handle_FillPathOld();
    void Handle_EOFillPath();
    void Handle_SetGray_Fill();
    void Handle_SetGray_Stroke();
    void Handle_SetExtendGraphState();
    void Handle_ClosePath();
    void Handle_SetFlat();
    void Handle_BeginImageData();
    void Handle_SetLineJoin();
    void Handle_SetLineCap();
    void Handle_SetCMYKColor_Fill();
    void Handle_SetCMYKColor_Stroke();
    void Handle_LineTo();
    void Handle_MoveTo();
    void Handle_SetMiterLimit();
    void Handle_MarkPlace();
    void Handle_EndPath();
    void Handle_SaveGraphState();
    void Handle_RestoreGraphState();
    void Handle_Rectangle();
    void Handle_SetRGBColor_Fill();
    void Handle_SetRGBColor_Stroke();
    void Handle_SetRenderIntent();
    void Handle_CloseStrokePath();
    void Handle_StrokePath();
    void Handle_SetColor_Fill();
    void Handle_SetColor_Stroke();
    void Handle_SetColorPS_Fill();
    void Handle_SetColorPS_Stroke();
    void Handle_ShadeFill();
    void Handle_SetCharSpace();
    void Handle_MoveTextPoint();
    void Handle_MoveTextPoint_SetLeading();
    void Handle_SetFont();
    void Handle_ShowText();
    void Handle_ShowText_Positioning();
    void Handle_SetTextLeading();
    void Handle_SetTextMatrix();
    void Handle_SetTextRenderMode();
    void Handle_SetTextRise();
    void Handle_SetWordSpace();
    void Handle_SetHorzScale();
    void Handle_MoveToNextLine();
    void Handle_CurveTo_23();
    void Handle_SetLineWidth();
    void Handle_Clip();
    void Handle_EOClip();
    void Handle_CurveTo_13();
    void Handle_NextLineShowText();
    void Handle_NextLineShowText_Space();
    void Handle_Invalid();

    CPDF_Document* const m_pDocument;
    CPDF_Dictionary* m_pPageResources;
    CPDF_Dictionary* m_pParentResources;
    CPDF_Dictionary* m_pResources;
    CPDF_PageObjects* m_pObjectList;
    int m_Level;
    CFX_AffineMatrix m_mtContentToUser;
    CFX_FloatRect m_BBox;
    CPDF_ParseOptions m_Options;
    _ContentParam m_ParamBuf1[PARAM_BUF_SIZE];
    FX_DWORD m_ParamStartPos;
    FX_DWORD m_ParamCount;
    FX_BOOL m_bAbort;
    CPDF_StreamParser* m_pSyntax;
    nonstd::unique_ptr<CPDF_AllStates> m_pCurStates;
    CPDF_ContentMark m_CurContentMark;
    CFX_PtrArray m_ClipTextList;
    CPDF_TextObject* m_pLastTextObject;
    FX_FLOAT m_DefFontSize;
    int m_CompatCount;
    FX_PATHPOINT* m_pPathPoints;
    int m_PathPointCount;
    int m_PathAllocSize;
    FX_FLOAT m_PathStartX;
    FX_FLOAT m_PathStartY;
    FX_FLOAT m_PathCurrentX;
    FX_FLOAT m_PathCurrentY;
    int m_PathClipType;
    CFX_ByteString m_LastImageName;
    CPDF_Image* m_pLastImage;
    CFX_BinaryBuf m_LastImageDict;
    CFX_BinaryBuf m_LastImageData;
    CPDF_Dictionary* m_pLastImageDict;
    CPDF_Dictionary* m_pLastCloneImageDict;
    FX_BOOL m_bReleaseLastDict;
    FX_BOOL m_bSameLastDict;
    FX_BOOL m_bColored;
    FX_FLOAT m_Type3Data[6];
    FX_BOOL m_bResourceMissing;
    CFX_PtrArray m_StateStack;
};
class CPDF_ContentParser
{
public:
    CPDF_ContentParser();
    ~CPDF_ContentParser();
    typedef enum { Ready, ToBeContinued, Done } ParseStatus;
    ParseStatus			GetStatus()
    {
        return m_Status;
    }
    void				Start(CPDF_Page* pPage, CPDF_ParseOptions* pOptions);
    void				Start(CPDF_Form* pForm, CPDF_AllStates* pGraphicStates, CFX_AffineMatrix* pParentMatrix,
                              CPDF_Type3Char* pType3Char, CPDF_ParseOptions* pOptions, int level);
    void				Continue(IFX_Pause* pPause);
    int					EstimateProgress();
protected:
    void				Clear();
    ParseStatus			m_Status;
    CPDF_PageObjects*	m_pObjects;
    FX_BOOL				m_bForm;
    CPDF_ParseOptions	m_Options;
    CPDF_Type3Char*		m_pType3Char;
    int					m_InternalStage;
    CPDF_StreamAcc*		m_pSingleStream;
    CPDF_StreamAcc**	m_pStreamArray;
    FX_DWORD			m_nStreams;
    uint8_t*			m_pData;
    FX_DWORD			m_Size;
    class CPDF_StreamContentParser*	m_pParser;
    FX_DWORD			m_CurrentOffset;
    CPDF_StreamFilter*	m_pStreamFilter;
};
class CPDF_AllStates : public CPDF_GraphicStates
{
public:
    CPDF_AllStates();
    ~CPDF_AllStates();
    void	Copy(const CPDF_AllStates& src);
    void	ProcessExtGS(CPDF_Dictionary* pGS, CPDF_StreamContentParser* pParser);
    void	SetLineDash(CPDF_Array*, FX_FLOAT, FX_FLOAT scale);
    CFX_AffineMatrix		m_TextMatrix, m_CTM, m_ParentMatrix;
    FX_FLOAT				m_TextX, m_TextY, m_TextLineX, m_TextLineY;
    FX_FLOAT				m_TextLeading, m_TextRise, m_TextHorzScale;
};

class CPDF_DocPageData
{
  public:
    explicit CPDF_DocPageData(CPDF_Document *pPDFDoc);
    ~CPDF_DocPageData();

    void                        Clear(FX_BOOL bRelease = FALSE);
    CPDF_Font*                  GetFont(CPDF_Dictionary* pFontDict, FX_BOOL findOnly);
    CPDF_Font*                  GetStandardFont(const CFX_ByteStringC& fontName, CPDF_FontEncoding* pEncoding);
    void                        ReleaseFont(CPDF_Dictionary* pFontDict);
    CPDF_ColorSpace*            GetColorSpace(CPDF_Object* pCSObj, CPDF_Dictionary* pResources);
    CPDF_ColorSpace*            GetCopiedColorSpace(CPDF_Object* pCSObj);
    void                        ReleaseColorSpace(CPDF_Object* pColorSpace);
    CPDF_Pattern*               GetPattern(CPDF_Object* pPatternObj, FX_BOOL bShading, const CFX_AffineMatrix* matrix);
    void                        ReleasePattern(CPDF_Object* pPatternObj);
    CPDF_Image*                 GetImage(CPDF_Object* pImageStream);
    void                        ReleaseImage(CPDF_Object* pImageStream);
    CPDF_IccProfile*            GetIccProfile(CPDF_Stream* pIccProfileStream);
    void                        ReleaseIccProfile(CPDF_IccProfile* pIccProfile);
    CPDF_StreamAcc*             GetFontFileStreamAcc(CPDF_Stream* pFontStream);
    void                        ReleaseFontFileStreamAcc(CPDF_Stream* pFontStream, FX_BOOL bForce = FALSE);
    FX_BOOL                     IsForceClear() const {return m_bForceClear;}
    CPDF_CountedColorSpace*     FindColorSpacePtr(CPDF_Object* pCSObj) const;
    CPDF_CountedPattern*        FindPatternPtr(CPDF_Object* pPatternObj) const;

  private:
    using CPDF_CountedFont = CPDF_CountedObject<CPDF_Font>;
    using CPDF_CountedIccProfile = CPDF_CountedObject<CPDF_IccProfile>;
    using CPDF_CountedImage = CPDF_CountedObject<CPDF_Image>;
    using CPDF_CountedStreamAcc = CPDF_CountedObject<CPDF_StreamAcc>;

    using CPDF_ColorSpaceMap = std::map<CPDF_Object*, CPDF_CountedColorSpace*>;
    using CPDF_FontFileMap = std::map<CPDF_Stream*, CPDF_CountedStreamAcc*>;
    using CPDF_FontMap = std::map<CPDF_Dictionary*, CPDF_CountedFont*>;
    using CPDF_IccProfileMap = std::map<CPDF_Stream*, CPDF_CountedIccProfile*>;
    using CPDF_ImageMap = std::map<FX_DWORD, CPDF_CountedImage*>;
    using CPDF_PatternMap = std::map<CPDF_Object*, CPDF_CountedPattern*>;

    CPDF_Document* const m_pPDFDoc;
    CFX_MapByteStringToPtr m_HashProfileMap;
    FX_BOOL m_bForceClear;

    CPDF_ColorSpaceMap m_ColorSpaceMap;
    CPDF_FontFileMap m_FontFileMap;
    CPDF_FontMap m_FontMap;
    CPDF_IccProfileMap m_IccProfileMap;
    CPDF_ImageMap m_ImageMap;
    CPDF_PatternMap m_PatternMap;
};

class CPDF_Function
{
public:
    static CPDF_Function*	Load(CPDF_Object* pFuncObj);
    virtual ~CPDF_Function();
    FX_BOOL		Call(FX_FLOAT* inputs, int ninputs, FX_FLOAT* results, int& nresults) const;
    int			CountInputs()
    {
        return m_nInputs;
    }
    int			CountOutputs()
    {
        return m_nOutputs;
    }
protected:
    CPDF_Function();
    int			m_nInputs, m_nOutputs;
    FX_FLOAT*	m_pDomains;
    FX_FLOAT*	m_pRanges;
    FX_BOOL		Init(CPDF_Object* pObj);
    virtual FX_BOOL	v_Init(CPDF_Object* pObj) = 0;
    virtual FX_BOOL	v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const = 0;
};
class CPDF_IccProfile
{
public:
    CPDF_IccProfile(const uint8_t* pData, FX_DWORD dwSize);
    ~CPDF_IccProfile();
    int32_t GetComponents() const { return m_nSrcComponents; }
    FX_BOOL					m_bsRGB;
    void*				m_pTransform;
private:
    int32_t                m_nSrcComponents;
};

class CPDF_DeviceCS : public CPDF_ColorSpace
{
public:
    CPDF_DeviceCS(CPDF_Document* pDoc, int family);

    FX_BOOL GetRGB(FX_FLOAT* pBuf,
                   FX_FLOAT& R,
                   FX_FLOAT& G,
                   FX_FLOAT& B) const override;
    FX_BOOL SetRGB(FX_FLOAT* pBuf,
                   FX_FLOAT R,
                   FX_FLOAT G,
                   FX_FLOAT B) const override;
    FX_BOOL v_GetCMYK(FX_FLOAT* pBuf,
                      FX_FLOAT& c,
                      FX_FLOAT& m,
                      FX_FLOAT& y,
                      FX_FLOAT& k) const override;
    FX_BOOL v_SetCMYK(FX_FLOAT* pBuf,
                      FX_FLOAT c,
                      FX_FLOAT m,
                      FX_FLOAT y,
                      FX_FLOAT k) const override;
    void TranslateImageLine(uint8_t* pDestBuf,
                            const uint8_t* pSrcBuf,
                            int pixels,
                            int image_width,
                            int image_height,
                            FX_BOOL bTransMask = FALSE) const override;
};

class CPDF_PatternCS : public CPDF_ColorSpace
{
public:
    explicit CPDF_PatternCS(CPDF_Document* pDoc)
        : CPDF_ColorSpace(pDoc, PDFCS_PATTERN, 1),
          m_pBaseCS(nullptr),
          m_pCountedBaseCS(nullptr) {
    }
    ~CPDF_PatternCS() override;
    FX_BOOL v_Load(CPDF_Document* pDoc, CPDF_Array* pArray) override;
    FX_BOOL GetRGB(FX_FLOAT* pBuf,
                   FX_FLOAT& R,
                   FX_FLOAT& G,
                   FX_FLOAT& B) const override;
    CPDF_ColorSpace* GetBaseCS() const override;

private:
    CPDF_ColorSpace* m_pBaseCS;
    CPDF_CountedColorSpace* m_pCountedBaseCS;
};

#endif  // CORE_SRC_FPDFAPI_FPDF_PAGE_PAGEINT_H_
